<?php

/**
 * Created by PhpStorm.
 * Script Name: Swoole.php
 * Create: 2022/11/1 11:09
 * Description:
 * Author: fudaoji<fdj@kuryun.cn>
 */

namespace app\common\coroutine;
use ky\ErrorCode;
use think\facade\Log;
use think\swoole\Server;

class Swoole extends Server
{
    protected $host = '0.0.0.0';
    protected $port = 9502;
    protected $serverType = 'tcp';
    protected $mode = SWOOLE_BASE;
    protected $option = [
        'worker_num'=> 2, //设置启动的Worker进程数,业务代码是全异步非阻塞的，这里设置为CPU核数的1-4倍最合理
        'daemonize'	=> false, //生产环境改为true
        'backlog'	=> 128,
        'task_worker_num' => 200,
        'max_request' => 500,
        'max_queued_bytes' => 128 * 1024 * 1024,
        'buffer_input_size' => 128 * 1024 * 1024,
        'buffer_output_size' => 128 * 1024 * 1024,
        'log_file'     => RUNTIME_PATH . 'swoole_server.log',
        "task_ipc_mode" => 3
    ];

    /**
     * @var object
     */
    private $redis;

    /*'Start', 'Shutdown', 'WorkerStart', 'WorkerStop', 'WorkerExit',
    // 'Connect', 'Receive', 'Packet', 'Close', 'BufferFull', 'BufferEmpty',
    // 'Task', 'Finish', 'PipeMessage', 'WorkerError', 'ManagerStart', 'ManagerStop',
    // 'Open', 'Message', 'HandShake', 'Request'
    */

    public function init()
    {
        parent::init(); // TODO: Change the autogenerated stub
        ini_set('memory_limit', '-1');
        model('common/setting')->settings();
        //一些初始化工作在此完成，例如读取数据库配置
        //$this->option['daemonize'] = config('app_debug') ? false : true;
        $config = config('system.develop');
        !empty($config['swoole_host']) && $this->host = $config['swoole_host'];
        !empty($config['swoole_port']) && $this->port = $config['swoole_port'];
        !empty($config['swoole_work_num']) && $this->option['worker_num'] = $config['swoole_work_num'];
        !empty($config['swoole_task_work_num']) && $this->option['task_worker_num'] = $config['swoole_task_work_num'];
        !empty($config['swoole_backlog']) && $this->option['backlog'] = $config['swoole_backlog'];
        !empty($config['swoole_max_request']) && $this->option['max_request'] = $config['swoole_max_request'];

        $this->swoole->set($this->option);
        //$this->redis = controller('common/base', 'event')->getRedis();

        //$this->swoole->atomic = new \Swoole\Atomic(0);
    }

    /**
     * 主进程启动
     * @param $server
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function onStart($server){
        echo "主进程启动:" . date("Y-m-d H:i:s") . PHP_EOL;
    }

    /**
     * 主进程启动
     * @param $server
     * Author: fudaoji<fdj@kuryun.cn>
     */
    /*public function onWorkStart($server){
        echo "work启动:" . date("Y-m-d H:i:s") . PHP_EOL;
    }*/

    /**
     * 收到任务
     * @param $server
     * @param $fd
     * @param $from_id
     * @param $data
     * Author: fudaoji<fdj@kuryun.cn>
     */
    public function onReceive($server, $fd, $from_id, $data)
    {
        //echo '收到数据' . PHP_EOL;
        try{
            $data = json_decode($data, true);
            if($data){
                $module = $data['module'];  //根据模块进行区别处理
                $class = '\\app\\common\\coroutine\\handler\\' . ucfirst($module). 'Handler';
                if (class_exists($class)) {
                    $obj = new $class;
                    if (method_exists($obj, 'onReceive')) {
                        $obj->onReceive($server, $fd, $from_id, $data);
                    }
                }
            }else{
                Log::error('no data');
            }
        }catch (\Exception $e){
            var_dump($e->getTraceAsString());
            var_dump($data);
        }
    }

    /**
     * 处理异步任务
     * Task进程内不能使用swoole_server->task方法
     * Task进程内不能使用swoole_mysql、swoole_redis、swoole_event等异步IO函数
     * @param $server
     * @param $task_id
     * @param $reactor_id
     * @param $data
     * Author: fudaoji<fdj@kuryun.cn>
     * @throws \Exception
     */
    public function onTask($server, $task_id, $reactor_id, $data) {
        //$this->redis->incr('task_num');
        //业务代码
        $module = $data['module'];  //根据模块进行区别处理
        $class = '\\app\\common\\coroutine\\handler\\' . ucfirst($module). 'Handler';
        if (class_exists($class)) {
            $obj = new $class;
            if (method_exists($obj, 'onTask')) {
                $obj->onTask($server, $task_id, $reactor_id, $data);
            }
        }
    }

    // 异步任务完成通知回调
    public function onFinish($server, $task_id, $data) {
        //echo('执行任务总数：' . $this->redis->get('task_num')) . PHP_EOL;
        //var_dump($data);

        $module = $data['module'];  //根据模块进行区别处理
        $class = '\\app\\common\\coroutine\\handler\\' . ucfirst($module). 'Handler';
        if (class_exists($class)) {
            $obj = new $class;
            if (method_exists($obj, 'onFinish')) {
                $obj->onFinish($server, $task_id, $data);
            }
        }
    }

    // 建立连接
    public function onConnect($server, $fd, $reactor_id) {
        echo "客户端连接成功:" . date("Y-m-d H:i:s") . PHP_EOL;
    }

    // 关闭连时回调函数
    public function onClose($server, $fd, $reactor_id) {
        echo "客户端关闭连接:" . date("Y-m-d H:i:s") . PHP_EOL;
    }
}